<template>
  <div class="grid-main">
    <el-table
      :data="gridData"
      stripe
      :border="border"
      :height="height"
      highlight-current-row
      class="grid"
      :row-key="rowKey"
      @selection-change="selectionChange"
      @current-change="currentChange"
    >
      <!-- 多选 -->
      <el-table-column v-if="multiple" type="selection" width="50" fixed />
      
      <!-- 显示操作表头标签 -->
      <el-table-column
        label="操作"
        v-if="operating != false && operating.length > 0"
        fixed="left"
        :width="getOperatingWidth"
      >
        <template slot-scope="scope">
          <el-link
            v-if="showBtn('info')"
            type="success"
            size="mini"
            @click="infoClick(scope.$index, scope.row)"
            icon="el-icon-document"
            >查看</el-link
          >
          <el-link
            v-if="showBtn('edit')"
            type="primary"
            size="mini"
            @click="editClick(scope.$index, scope.row)"
            icon="el-icon-edit"
            :style="showBtn('edit') && showBtn('info') ? {'marginLeft':'10px'} : {}"
            >编辑</el-link
          >
          <el-popconfirm
            v-if="!multiple && showBtn('delete') && !multiple"
            title="确定删除吗？"
            @confirm="handleDelete(scope.$index, scope.row)"
            :style="showBtn('edit') && !multiple && showBtn('delete') && !multiple ? {'marginLeft':'10px'} : {}"
          >
            <el-link
              slot="reference"
              size="mini"
              type="danger"
              icon="el-icon-delete"
              >删除</el-link
            >
          </el-popconfirm>
        </template>
      </el-table-column>
      <el-table-column label="序号" type="index" width="50" fixed />
      <!-- 循环字段 -->
      <template v-for="(col, i) in columns">
        <!-- 字典类字段显示 -->
        <el-table-column
          v-if="col.dictName"
          :key="i"
          :prop="col.prop"
          :label="col.label"
          :fixed="getFixed(col.prop)"
          :sort="getSort(col.prop)"
          :width="col.width"
        >
          <template slot-scope="scope">
            <div slot="reference">
              <el-tag
                v-for="(item, i) in getDictList(scope.row[col.prop])"
                size="small"
                style="margin-right:5px;margin-bottom:5px;"
                :key="i"
              >
                
                {{ getTitle(col.dictName, item) }}
              </el-tag>
            </div>
          </template>
        </el-table-column>
        <!-- 日期类字段显示 -->
        <el-table-column
          v-else-if="col.format"
          :key="i"
          :prop="col.prop"
          :label="col.label"
          :fixed="getFixed(col.prop)"
          :sort="getSort(col.prop)"
          :width="col.width"
        >
          <template slot-scope="scope" v-if="col.format">
            {{ $moment(scope.row[col.prop]).format(col.format) }}
          </template>
        </el-table-column>
        <!-- 其他普通字段显示 -->
        <el-table-column
          v-else
          :key="i"
          :prop="col.prop"
          :label="col.label"
          :fixed="getFixed(col.prop)"
          :sort="getSort(col.prop)"
          :width="col.width"
        >
        </el-table-column>
      </template>
    </el-table>
    <el-pagination
      @size-change="pageSizeChange"
      @current-change="pageCurrentChange"
      :current-page="pageNoData"
      :page-sizes="[10, 20, 50, 100, 500]"
      :page-size="pageSizeData"
      layout="total, sizes, prev, pager, next, jumper"
      :total="total"
      class="pagination"
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
  model: {
    prop: "selection",
    methods: ["load", "del"],
  },
  props: {
    tableName: {type:String},
    sysName: {type:String},
    queryParams: {
      type: Object,
      default: () => {
        return {};
      },
    },
    size: {
      type: String,
      validator: function(value) {
        return (
          ["medium", "small", "mini"].findIndex((item) => item == value) >= 0
        );
      },
      default: "medium",
    },
    border: { type: Boolean, default: false },
    rowKey: { type: String, required: true },
    multiple: { type: Boolean, default: false },
    sorts: {
      type: [Array, String],
      default: () => "no",
      validator: function(value) {
        return (
          ["all", "no"].findIndex((item) => item == value) >= 0 ||
          Array.isArray(value)
        );
      },
    },
    pageSize: { type: Number, default: 20 },
    pageNo: { type: Number, default: 1 },
    height: Number,
    fixeds: { type: Array, default: () => [] },
    operating: {
      type: [Array, Boolean],
      validator: function(arr) {
        const list = ["edit", "delete", "info"];
        for (let i = 0; i < arr.length; i++) {
          if (list.findIndex((item) => item == arr[i]) < 0) {
            console.error(
              '/src/pages/main/components/grid/Grid.vue 属性检查失败，属性operating的值只能是false或数组["edit", "delete"]'
            );
            return false;
          }
        }
        if (arr == true) {
          console.error(
            '/src/pages/main/components/grid/Grid.vue Grid.vue属性检查失败，属性operating的值只能是false或数组["edit", "delete"]'
          );
          return false;
        }
        return true;
      },
      default: () => ["edit", "delete"],
    },
    infoClick: {
      type: Function,
      default: (index, row) => {
        console.log('查看按钮点击',index, row);
      },
    },
    editClick: {
      type: Function,
      default: (index, row) => {
        console.log('编辑按钮点击',index, row);
      },
    },
    deleteClick: {
      type: Function,
    },
    columns: {
      type: Array,
      required: true,
      validator: function(item) {
        for (let i = 0; i < item.length; i++) {
          if (!item[i].hasOwnProperty("label")) {
            console.error(
              "/src/pages/main/components/grid/Grid.vue Grid.vue属性检查失败，表格组件的列（columns）属性缺失(label)属性值!",
              item[i]
            );
            return false;
          }
          if (!item[i].hasOwnProperty("prop")) {
            console.error(
              "/src/pages/main/components/grid/Grid.vue Grid.vue属性检查失败，表格组件的列（columns）属性缺失(prop)属性值!",
              item[i]
            );
            return false;
          }
        }
        return true;
      },
    },
  },
  data() {
    return {
      //表格数据
      gridData: [],
      //选择列表-该组件的v-model
      selection: [],
      //当前选中行
      currentRow: null,
      //数据总量
      total: 0,
      //临时存储所有使用的字典
      dicts: {},
      //分页大小
      pageSizeData: this.pageSize,
      //当前页
      pageNoData: this.pageNo,
    };
  },
  computed:{
    getOperatingWidth(){
      if (Array.isArray(this.operating)){
        return this.operating.length*70
      }else{
        return 210
      }
    }
  },
  methods: {
    //根据字段名返回是否为排序字段
    getSort(prop) {
      if (this.sorts == "no") {
        return false;
      } else if (this.sorts == "all") {
        return true;
      } else {
        return this.sorts.findIndex((item) => item == prop) >= 0;
      }
    },
    //根据字段名返回是否为锁定列
    getFixed(prop) {
      return this.fixeds.findIndex((item) => item == prop) >= 0;
    },
    //返回数组形式的字典列表，如果是字符串自动用逗号转换成数组
    getDictList(data) {
      if (typeof data != "undefined") {
        if (Array.isArray(data)) {
          return data;
        } else if (typeof data == "string") {
          if (data.indexOf(",") >= 0) {
            return data.split(",");
          } else {
            return [data];
          }
        } else {
          return [data];
        }
      }
      return [];
    },
    //判断是否要显示相应的按钮
    showBtn(btn) {
      if (typeof this.operating != "undefined") {
        if (this.operating.indexOf(btn) >= 0) {
          return true;
        }
      }
      return false;
    },
    //返回字典值
    getTitle(dictName, val) {
      if (typeof val != "undefined") {
        const list = this.dicts[dictName];
        if (Array.isArray(list)) {
          const obj = list.find((item) => item.code == val);
          if (typeof obj != "undefined") {
            return obj.title;
          }
        }
      }
      return "";
    },
    //多选选项改变时记录
    selectionChange(val) {
      this.selection = val;
    },
    //当前选中记录改变时记录
    currentChange(val) {
      this.currentRow = val;
    },
    //删除按钮点击
    handleDelete(index, row) {
      if (typeof this.deleteClick != "undefined") {
        this.deleteClick(row);
      } else {
        this.del(row);
      }
    },
    //分页大小改变时
    pageSizeChange(val) {
      this.pageSizeData = val;
      this.load({
        ...this.queryParams,
        pageSize: this.pageSizeData,
        pageNo: this.pageNoData,
      });
    },
    // 当前页改变时
    pageCurrentChange(val) {
      this.pageNoData = val;
      this.load({
        ...this.queryParams,
        pageSize: this.pageSizeData,
        pageNo: this.pageNoData,
      });
    },
    // 载入数据
    load(queryParams) {
      this.$api.find(this.sysName,this.tableName, queryParams).then((data) => {
        const { success, result, code, msg } = data;
        if (success) {
          this.gridData = result.rows;
          this.total = result.total;
        } else {
          this.$msg(`${msg},错误代码:${code}`);
        }
      });
    },
    // 删除数据
    del(row) {
      if (this.multiple) {
        let list = [];
        for (let i = 0; i < this.selection.length; i++) {
          list.push(this.selection[i][this.rowKey]);
        }
        this.$api.post(this.url||'/api/delete/'+this.tableName, { id: list }).then((data) => {
          const { success, result, code, msg } = data;
          if (success) {
            this.load({
              ...this.queryParams,
              pageSize: this.pageSizeData,
              pageNo: this.pageNoData,
            });
          } else {
            this.$msg(`${msg},错误代码:${code}`);
          }
        });
      } else {
        this.$api
          .post(this.url||'/api/delete/'+this.tableName, { id: row[this.rowKey] })
          .then((data) => {
            const { success, result, code, msg } = data;
            if (success) {
              this.load({
                ...this.queryParams,
                pageSize: this.pageSizeData,
                pageNo: this.pageNoData,
              });
            } else {
              this.$msg(`${msg},错误代码:${code}`);
            }
          });
      }
    },
  },
  mounted() {
    // 初始化数据
    this.load({
      ...this.queryParams,
      pageSize: this.pageSizeData,
      pageNo: this.pageNoData,
    });
  },
  created() {
    // 初始化字典
    this.columns.forEach(async (item) => {
      if (item.dictName) {
        this.dicts[item.dictName] = await this.$dict.getList(item.dictName);
      }
    });
  },
  watch: {
    queryParams(val) {
      if (typeof val == "object") {
        this.load({
          ...val,
          pageSize: this.pageSizeData,
          pageNo: this.pageNoData,
        });
      }
    },
    currentRow(val) {
      if (!this.multiple) {
        this.selection = [val];
      }
    },
    selection(val) {
      this.$emit("input", val);
    },
  },
};
</script>

<style lang="less" scoped>
.grid-main {
  border: 1px solid #ececec;
  border-radius: 3px;
}
.grid {
  width: 100%;
}
.pagination {
  text-align: right;
  background-color: #f2f2f2;
  padding-right: 20px;
}
</style>

TODO:
该组件需要增加详情显示的属性、link和方法，属性可以是String表示某字段，也可以是Boolean出现呢单独的Link
TODO: 详情显示应该给出对应回调方法，并返回当前记录的所有字段信息
